/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    dev_i2c.h
 *  @brief   Designware i2c device interface header file
 *  @version v1.0
 *  @date    03. Apr. 2023
 *  @author  liuchao
 ****************************************************************/

#ifndef __DEV_I2C_H__
#define __DEV_I2C_H__

#include "bits.h"
#include "dev_common.h"

/**
 * @defgroup	DEVICE_HAL_I2C_CFG	I2C Related Configurations
 * @ingroup	DEVICE_HAL_I2C
 * @brief	Macros for I2C device related configurations.
 * During I2C device during implementation, it is recommended that
 * when user set i2c speed to a speed maybe not supported in your
 * i2c device, device driver will set to a supported slower speed.
 * @{
 */
/** I2C Bus possible speed modes */
typedef enum i2c_speed_mode {
	I2C_SPEED_STANDARD      = 0,    /*!< Bidirectional, Standard-mode (Sm), with a bit rate up to 100 kbit/s */
	I2C_SPEED_FAST          = 1,    /*!< Bidirectional, Fast-mode (Fm), with a bit rate up to 400 kbit/s */
	I2C_SPEED_FASTPLUS      = 2,    /*!< Bidirectional, Fast-mode Plus (Fm+), with a bit rate up to 1 Mbit/s */
	I2C_SPEED_HIGH          = 3,    /*!< Bidirectional, High-speed mode (Hs-mode), with a bit rate up to 3.4 Mbit/s */
	I2C_SPEED_ULTRA         = 4     /*!< Unidirectional(Write only), Ultra Fast-mode (UFm), with a bit rate up to 5 Mbit/s */
} I2C_SPEED_MODE;

/** I2C next Condition */
typedef enum i2c_next_condtion {
	I2C_MODE_STOP           = 0,    /*!< Send a STOP condition after write/read operation */
	I2C_MODE_RESTART        = 1,    /*!< Send a RESTART condition after write/read operation */
} I2C_NEXT_CONDTION;

/** I2C Error State */
typedef enum i2c_error_state {
	I2C_ERR_NONE            = 0,    /*!< Currently in i2c device free state */
	I2C_ERR_LOST_BUS        = 1,    /*!< Master or slave lost bus during operation */
	I2C_ERR_ADDR_NOACK      = 2,    /*!< Slave address is sent but not addressed by any slave devices */
	I2C_ERR_DATA_NOACK      = 3,    /*!< Data in transfer is not acked when it should be acked */
	I2C_ERR_TIMEOUT         = 4,    /*!< Transfer timeout, no more data is received or sent */
	I2C_ERR_MSTSTOP         = 5,    /*!< Slave received a STOP condition from master device */
	I2C_ERR_UNDEF           = 6     /*!< Undefined error cases */
} I2C_ERROR_STATE;

/** I2C Working State */
typedef enum i2c_working_state {
	I2C_FREE        = 0,    /*!< Currently in i2c device free state */
	I2C_IN_TX       = 1,    /*!< Currently in i2c master transmit state */
	I2C_IN_RX       = 2     /*!< Currently in i2c master receive state */
} I2C_WORKING_STATE;

/** I2C Addressing Mode */
typedef enum i2c_address_mode {
	I2C_7BIT_ADDRESS        = 0,    /*!< Use 7bit address mode */
	I2C_10BIT_ADDRESS       = 1     /*!< Use 10bit address mode */
} I2C_ADDRESS_MODE;

/** I2C Slave State */
typedef enum i2c_slave_state {
	I2C_SLAVE_STATE_FREE    = 0,            /*!< None state, in free */
	I2C_SLAVE_STATE_START   = BIT(1),     /*!< Start or Restart condition, clear it when read */
	I2C_SLAVE_STATE_STOP    = BIT(2),     /*!< Stop condition, clear it when read */
	I2C_SLAVE_STATE_RD_REQ  = BIT(3),     /*!< Read request from master, this will trigger the slave transmit callback */
	I2C_SLAVE_STATE_RD_DONE = BIT(4),     /*!< Read request done from master, clear it when read */
	I2C_SLAVE_STATE_WR_REQ  = BIT(5),     /*!< Write request from master, this will trigger the slave receive callback */
	I2C_SLAVE_STATE_GC_REQ  = BIT(6),     /*!< General call request from master */
	I2C_SLAVE_STATE_ERROR   = BIT(7)      /*!< Error, clear it when read */
} I2C_SLAVE_STATE;

/** 7bit I2C address mask */
#define I2C_7BIT_ADDRESS_MASK           (0x7F)
/** 10bit I2C address mask */
#define I2C_10BIT_ADDRESS_MASK          (0x3FF)
/** @} */

/**
 * @defgroup	DEVICE_HAL_I2C_CTRLCMD		I2C Device Control Commands
 * @ingroup	DEVICE_HAL_I2C
 * @brief	Definitions for i2c control command, used in @ref dev_i2c::i2c_control "I2C IO Control"
 * @details	These commands defined here can be used in user code directly.
 * - Parameters Usage
 *   - For passing parameters like integer, just use uint32_t/int32_t to directly pass values
 *   - For passing parameters for a structure, please use pointer to pass values
 *   - For getting some data, please use pointer to store the return data
 * - Common Return Values
 *   - @ref E_OK,	Control device successfully
 *   - @ref E_CLSED,	Device is not opened
 *   - @ref E_OBJ,	Device object is not valid or not exists
 *   - @ref E_PAR,	Parameter is not valid for current control command
 *   - @ref E_SYS,	Control device failed, due to hardware issues such as device is disabled
 *   - @ref E_CTX,	Control device failed, due to different reasons like in transfer state
 *   - @ref E_NOSPT,	Control command is not supported or not valid
 * @{
 */

/** Define I2C control commands for common usage */
#define DEV_SET_I2C_SYSCMD(cmd)         DEV_SET_SYSCMD((cmd))
/** Define I2C control commands for master usage */
#define DEV_SET_I2C_MST_SYSCMD(cmd)     DEV_SET_SYSCMD(0x00004000 | (cmd))
/** Define I2C control commands for slave usage */
#define DEV_SET_I2C_SLV_SYSCMD(cmd)     DEV_SET_SYSCMD(0x00008000 | (cmd))

/* ++++ Common commands for I2C Device ++++ */
/**
 * Get @ref dev_i2c_info::status "current device status"
 * - Param type : uint32_t *
 * - Param usage : store result of current status
 * - Return value explanation :
 */
#define I2C_CMD_GET_STATUS                      DEV_SET_I2C_SYSCMD(0)
/**
 * Set @ref dev_i2c_info::addr_mode "i2c addressing mode".
 * - Param type : uint32_t
 * - Param usage : i2c addressing mode, possible values can be found @ref I2C_ADDRESS_MODE "here"
 * - Return value explanation :
 */
#define I2C_CMD_SET_ADDR_MODE                   DEV_SET_I2C_SYSCMD(1)
/**
 * Set @ref dev_i2c_cbs::tx_cb "i2c transmit success callback" function
 * when all required bytes are transmitted for interrupt method
 * - Param type : @ref DEV_CALLBACK * or NULL
 * - Param usage : transmit success callback function for i2c
 * - Return value explanation :
 */
#define I2C_CMD_SET_TXCB                        DEV_SET_I2C_SYSCMD(2)
/**
 * Set @ref dev_i2c_cbs::rx_cb "i2c receive success callback" function
 * when all required bytes are received for interrupt method
 * - Param type : @ref DEV_CALLBACK * or NULL
 * - Param usage : receive success callback function for i2c
 * - Return value explanation :
 */
#define I2C_CMD_SET_RXCB                        DEV_SET_I2C_SYSCMD(3)
/**
 * Set @ref dev_i2c_cbs::err_cb "i2c transfer error callback" function
 * when something error happened for interrupt method
 * - Param type : @ref DEV_CALLBACK * or NULL
 * - Param usage : transfer error callback function for i2c
 * - Return value explanation :
 */
#define I2C_CMD_SET_ERRCB                       DEV_SET_I2C_SYSCMD(4)
/**
 * Set buffer for interrupt transmit, and it will set @ref dev_i2c_info::tx_buf "tx_buf".
 * - I2C master mode use case  \n
 *    For master mode, if you set tx buffer to NULL, when tx interrupt is enabled and entered into tx interrupt,
 * it will automatically disable the tx interrupt, so when you want to transfer something, you need to set the
 * tx buffer to Non-NULL and enable tx interrupt, when the tx buffer is sent, it will disable the tx interrupt
 * and call tx callback function if available.
 * - I2C slave mode use case   \n
 *    For slave mode, the tx buffer is not used, only tx callback function is used, and if tx callback is not set,
 * then it will automatically disable the tx interrupt, if tx callback is set, it will call the tx callback function
 * and you need to write or read in the tx callback function, to avoid meaningless waiting, you can use control command
 * @ref I2C_CMD_GET_TXAVAIL to get how many bytes space existing in transmit fifo, and use i2c_write to send the available
 * bytes.
 * - Param type : DEV_BUFFER * or NULL
 * - Param usage : buffer structure pointer, if param is NULL, then it will set tx_buf to NULL
 * - Return value explanation :
 */
#define I2C_CMD_SET_TXINT_BUF                   DEV_SET_I2C_SYSCMD(5)
/**
 * Set buffer for interrupt receive, and it will set @ref dev_i2c_info::rx_buf "rx_buf"
 * - I2C master mode use case  \n
 *   Similar to @ref I2C_CMD_SET_TXINT_BUF
 * - I2C slave mode use case   \n
 *   Similiar to @ref I2C_CMD_SET_TXINT_BUF
 * - Param type : DEV_BUFFER * or NULL
 * - Param usage : buffer structure pointer, if param is NULL, then it will set rx_buf to NULL
 * - Return value explanation :
 */
#define I2C_CMD_SET_RXINT_BUF                   DEV_SET_I2C_SYSCMD(6)
/**
 * Enable or disable transmit interrupt,
 * for master mode, only one of tx and rx interrupt can be enabled,
 * if tx interrupt is enabled, then rx interrupt can't be changed.
 * - Param type : uint32_t
 * - Param usage : enable(none-zero) or disable(zero) flag
 * - Return value explanation :
 */
#define I2C_CMD_SET_TXINT                       DEV_SET_I2C_SYSCMD(7)
/**
 * Enable or disable receive interrupt,
 * for master mode, only one of tx and rx interrupt can be enabled,
 * if rx interrupt is enabled, then tx interrupt can't be changed.
 * - Param type : uint32_t
 * - Param usage : enable(none-zero) or disable(zero) flag
 * - Return value explanation :
 */
#define I2C_CMD_SET_RXINT                       DEV_SET_I2C_SYSCMD(8)
/**
 * Abort current interrupt transmit operation if tx interrupt enabled,
 * it will disable transmit interrupt, and set @ref DEV_IN_TX_ABRT
 * in @ref dev_i2c_info::status "status" variable,
 * and call the transmit callback function, when tx callback is finished,
 * it will clear @ref DEV_IN_TX_ABRT and return
 * - Param type : NULL
 * - Param usage :
 * - Return value explanation :
 */
#define I2C_CMD_ABORT_TX                        DEV_SET_I2C_SYSCMD(9)
/**
 * Abort current interrupt receive operation if rx interrupt enabled,
 * it will disable receive interrupt, and set @ref DEV_IN_TX_ABRT
 * in @ref dev_i2c_info::status "status" variable,
 * and call the receive callback function, when rx callback is finished,
 * it will clear @ref DEV_IN_TX_ABRT and return
 * - Param type : NULL
 * - Param usage :
 * - Return value explanation :
 */
#define I2C_CMD_ABORT_RX                        DEV_SET_I2C_SYSCMD(10)
/**
 * Do a software reset for I2C device, it will stop current transfer,
 * and clear error state and bring device to normal state, set next condition to STOP
 * - Param type : NULL
 * - Param usage :
 * - Return value explanation :
 */
#define I2C_CMD_RESET                           DEV_SET_I2C_SYSCMD(11)
/**
 * Flush i2c device transmit buffer or fifo
 * - Param type : NULL
 * - Param usage :
 * - Return value explanation :
 */
#define I2C_CMD_FLUSH_TX                        DEV_SET_I2C_SYSCMD(12)
/**
 * Flush i2c device receive buffer or fifo
 * - Param type : NULL
 * - Param usage :
 * - Return value explanation :
 */
#define I2C_CMD_FLUSH_RX                        DEV_SET_I2C_SYSCMD(13)
/**
 * Enable i2c device
 * - Param type : NULL
 * - Param usage : param is not required
 * - Return value explanation :
 */
#define I2C_CMD_ENA_DEV                         DEV_SET_I2C_SYSCMD(14)
/**
 * Disable i2c device, when device is disabled,
 * only @ref I2C_CMD_ENA_DEV, @ref I2C_CMD_DIS_DEV,
 * @ref I2C_CMD_GET_STATUS and @ref I2C_CMD_RESET
 * commands can be executed, other commands will return @ref E_SYS
 * - Param type : NULL
 * - Param usage : param is not required
 * - Return value explanation :
 */
#define I2C_CMD_DIS_DEV                         DEV_SET_I2C_SYSCMD(15)
/**
 * Get how many bytes space in i2c are available to transmit,
 * this can be used in interrupt callback functions,
 * cooperate with @ref dev_i2c::i2c_write "i2c_write" API to realize non-blocked write
 * - Param type : int32_t *
 * - Param usage : store the write available bytes, > 0 for available bytes, 0 for not available
 * - Return value explaination :
 */
#define I2C_CMD_GET_TXAVAIL                     DEV_SET_I2C_SYSCMD(16)
/**
 * Get how many bytes in i2c are available to receive,
 * this can be used in interrupt callback functions,
 * cooperate with @ref dev_i2c::i2c_read "i2c_read" API to realize non-blocked read
 * - Param type : int32_t *
 * - Param usage : store the read available bytes, > 0 for available bytes, 0 for not available
 * - Return value explanation :
 */
#define I2C_CMD_GET_RXAVAIL                     DEV_SET_I2C_SYSCMD(17)
/**
 * request dma rx and tx channels
 * this can be used transfer data using dma
 * - Param type : NULL
 * - Param usage : param is not required
 * - Return value explanation :
 */
#define I2C_CMD_REQ_DMA_CHAN                    DEV_SET_I2C_SYSCMD(18)


/* ++++ Master only commands for I2C Device ++++ */
/**
 * Set @ref dev_i2c_info::speed_mode "i2c speed mode".
 * - Param type : uint32_t
 * - Param usage : i2c speed mode, possible values can be found @ref I2C_SPEED_MODE "here",
 * and if passing mode is not supported, it will choose a lower supported speed mode
 * - Return value explanation :
 */
#define I2C_CMD_MST_SET_SPEED_MODE              DEV_SET_I2C_MST_SYSCMD(0)
/**
 * Set next condition for following transmit or receive operation.
 * For example, you can change next condition before i2c_read or i2c_write,
 * then in i2c_read/i2c_write operation, it will send a STOP/RESTART condition
 * after the last byte of this operation. For interrupt, this is similar.
 * - Param type : uint32_t
 * - Param usage : next condition can be @ref I2C_NEXT_CONDTION
 * - Return value explanation :
 */
#define I2C_CMD_MST_SET_NEXT_COND               DEV_SET_I2C_MST_SYSCMD(1)
/**
 * Set target slave device address for selecting slave device
 * - Param type : uint32_t
 * - Param usage : target slave address value
 * - Return value explanation :
 */
#define I2C_CMD_MST_SET_TAR_ADDR                DEV_SET_I2C_MST_SYSCMD(2)

/* ++++ Slave only commands for I2C Device ++++ */
/**
 * Set slave address when working as slave i2c device
 * - Param type : uint32_t
 * - Param usage : slave address value
 * - Return value explanation :
 */
#define I2C_CMD_SLV_SET_SLV_ADDR                DEV_SET_I2C_SLV_SYSCMD(0)
/**
 * Get @ref i2c_slave_state "slave state" when working as slave i2c device
 * - Param type : uint32_t *
 * - Param usage : slave state
 * - Return value explanation :
 */
#define I2C_CMD_SLV_GET_SLV_STATE               DEV_SET_I2C_SLV_SYSCMD(1)

/** @} */

/**
 * @defgroup	DEVICE_HAL_I2C_CALLBACK	I2C Interrupt callback functions
 * @ingroup	DEVICE_HAL_I2C
 * @brief	callback function structure for I2C device
 * @{
 */
typedef struct dev_i2c_cbs {
	DEV_CALLBACK tx_cb;     /*!< i2c data transmit success required bytes callback */
	DEV_CALLBACK rx_cb;     /*!< i2c data receive success required bytes callback */
	DEV_CALLBACK err_cb;    /*!< i2c error callback */
} DEV_I2C_CBS, *DEV_I2C_CBS_PTR;
/** @} */

/**
 * @defgroup	DEVICE_HAL_I2C_DEVSTRUCT	I2C Device Structure
 * @ingroup	DEVICE_HAL_I2C
 * @brief	contains definitions of i2c device structure.
 * @details	this structure will be used in user implemented code, which was called
 *     Device Driver Implement Layer for i2c to realize in user code.
 * @{
 */
/**
 * @brief	i2c information struct definition
 * @details	informations about i2c open state, working state,
 * 	baurate, i2c registers, working method, interrupt number
 */
typedef struct dev_i2c_info {
	void *i2c_ctrl;         /*!< i2c control related pointer, implemented by bsp developer, and this should be set during i2c object implementation */
	uint32_t opn_cnt;       /*!< i2c open count, open it will increase 1, close it will decrease 1, 0 for close, >0 for open */
	uint32_t status;        /*!< current working status, refer to @ref DEVICE_HAL_COMMON_DEVSTATUS, this should be @ref DEV_ENABLED for first open */
	uint32_t mode;          /*!< current working mode, which can be @ref DEV_MASTER_MODE "master mode" or @ref DEV_SLAVE_MODE "slave mode" */
	uint32_t speed_mode;    /*!< current working @ref I2C_SPEED_MODE "i2c speed mode" */
	uint32_t cur_state;     /*!< @ref I2C_WORKING_STATE "current working state for i2c device", this should be @ref I2C_FREE for first open */
	uint32_t err_state;     /*!< @ref I2C_ERROR_STATE "current error state for i2c device", this should be @ref I2C_ERR_NONE for first open */
	uint32_t addr_mode;     /*!< @ref I2C_ADDRESS_MODE "current addressing mode", this should be @ref I2C_7BIT_ADDRESS for first open */
	uint32_t slv_addr;      /*!< slave address when working as slave i2c device, this should be 0 for first open */
	uint32_t tar_addr;      /*!< target slave device address when addressing that slave device, this should be 0 for first open */
	uint32_t next_cond;     /*!< @ref I2C_NEXT_CONDTION "next condition for master transmit or receive", \
	                                possible values are STOP or RESTART, it should be STOP for first open */
	DEV_BUFFER tx_buf;      /*!< transmit buffer via interrupt, this should be all zero for first open */
	DEV_BUFFER rx_buf;      /*!< receive buffer via interrupt, this should be all zero for first open */
	DEV_I2C_CBS i2c_cbs;    /*!< i2c callbacks, for both master and slave mode, this should be all NULL for first open */
	void *extra;            /*!< a extra pointer to get hook to applications which should not used by bsp developer,
	                                this should be NULL for first open and you can @ref DEV_I2C_INFO_SET_EXTRA_OBJECT "set"
	                                or @ref DEV_I2C_INFO_GET_EXTRA_OBJECT "get" the extra information pointer */
	bool hasdma;            /*dma enable*/
	uint8_t dma_tx_chan;    /*dma tx channel*/
	uint8_t dma_rx_chan;    /*dma rx channel*/
	uint32_t drqline;       /*dma device num*/
} DEV_I2C_INFO, *DEV_I2C_INFO_PTR;

/** Set extra information pointer of i2c info */
#define DEV_I2C_INFO_SET_EXTRA_OBJECT(i2c_info_ptr, extra_info)         (i2c_info_ptr)->extra = (void *)(extra_info)
/** Get extra information pointer of i2c info */
#define DEV_I2C_INFO_GET_EXTRA_OBJECT(i2c_info_ptr)                     ((i2c_info_ptr)->extra)

/**
 * @brief	i2c device interface definition
 * @details	define i2c device interface, like i2c information structure,
 * 	fuctions to get i2c info, open/close/control i2c, send/receive data by i2c
 * @note	all this details are implemented by user in user porting code
 */
typedef struct dev_i2c {
	DEV_I2C_INFO i2c_info;                                  /*!< i2c device information */
	int32_t (*i2c_open)(uint32_t mode, uint32_t param);     /*!< open i2c device in master/slave mode, \
	                                                                when in master mode, param stands for speed mode, \
	                                                                when in slave mode, param stands for slave address */
	int32_t (*i2c_close)(void);                             /*!< close i2c device */
	int32_t (*i2c_control)(uint32_t ctrl_cmd, void *param); /*!< control i2c device */
	int32_t (*i2c_write)(const void *data, uint32_t len);   /*!< send data by i2c device (blocking method) */
	int32_t (*i2c_read)(void *data, uint32_t len);          /*!< read data from i2c device (blocking method) */
} DEV_I2C, *DEV_I2C_PTR;

/**
 * @fn		int32_t (* dev_i2c::i2c_open) (uint32_t mode, uint32_t param)
 * @details	open an i2c device with selected mode (master or slave) with defined param
 * @param[in]	mode	working mode (@ref DEV_MASTER_MODE "master" or @ref DEV_SLAVE_MODE "slave")
 * @param[in]	param	When mode is @ref DEV_MASTER_MODE, param stands for @ref dev_i2c_info::speed_mode "speed mode",
 * 			when mode is @ref DEV_SLAVE_MODE, param stands for @ref dev_i2c_info::slv_addr "slave device 7bit address"
 * @retval	E_OK	Open successfully without any issues
 * @retval	E_OPNED	If device was opened before with different parameters,
 *			then just increase the @ref dev_i2c_info::opn_cnt "opn_cnt" and return @ref E_OPNED
 * @retval	E_OBJ	Device object is not valid
 * @retval	E_SYS	Device is opened for different mode before, if you want to open it with different mode, you need to fully close it first.
 * @retval	E_PAR	Parameter is not valid
 * @retval	E_NOSPT	Open settings are not supported
 */

/**
 * @fn		int32_t (* dev_i2c::i2c_close) (void)
 * @details	close an i2c device, just decrease the @ref dev_i2c_info::opn_cnt "opn_cnt",
 *      if @ref dev_i2c_info::opn_cnt "opn_cnt" equals 0, then close the device
 * @retval	E_OK	Close successfully without any issues(including scenario that device is already closed)
 * @retval	E_OPNED	Device is still opened, the device @ref dev_i2c_info::opn_cnt "opn_cnt" decreased by 1
 * @retval	E_OBJ	Device object is not valid
 */

/**
 * @fn		int32_t (* dev_i2c::i2c_control) (uint32_t ctrl_cmd, void *param)
 * @details	control an i2c device by ctrl_cmd, with passed param.
 * 	you can control i2c device using predefined i2c control commands defined using @ref DEV_SET_SYSCMD
 * 	(which must be implemented by bsp developer), such as @ref I2C_CMD_MST_SET_SPEED_MODE "set i2c speed mode",
 * 	@ref I2C_CMD_FLUSH_TX "flush tx" and @ref DEVICE_HAL_I2C_CTRLCMD "more".
 * 	And you can also control i2c device using your own specified commands defined using @ref DEV_SET_USRCMD,
 * 	but these specified commands should be defined in your own i2c device driver implementation.
 * @param[in]		ctrl_cmd	@ref DEVICE_HAL_I2C_CTRLCMD "control command", to change or get some thing related to i2c
 * @param[in,out]	param		parameters that maybe argument of the command,
 * 					or return values of the command, must not be NULL
 * @retval	E_OK	Control device successfully
 * @retval	E_CLSED	Device is not opened
 * @retval	E_OBJ	Device object is not valid or not exists
 * @retval	E_PAR	Parameter is not valid for current control command
 * @retval	E_SYS	Control device failed, due to hardware issues, such as device is disabled
 * @retval	E_CTX	Control device failed, due to different reasons like in transfer state
 * @retval	E_NOSPT	Control command is not supported or not valid
 */

/**
 * @fn		int32_t (* dev_i2c::i2c_write) (const void *data, uint32_t len)
 * @details	send data through i2c with defined len to slave device which slave address is slv_addr.
 * @param[in]	data	pointer to data need to send by i2c
 * @param[in]	len	length of data to be sent
 * @retval	>0	Byte count that was successfully sent for poll method,
 * 			it might can't send that much due to @ref dev_i2c_info::err_state "different error state".
 * @retval	E_OBJ	Device object is not valid or not exists
 * @retval	E_PAR	Parameter is not valid
 * @retval	E_CTX	Device is still in transfer state
 * @retval	E_SYS	Can't write data to hardware due to hardware issues, such as device is disabled
 */

/**
 * @fn		int32_t (* dev_i2c::i2c_read) (void *data, uint32_t len)
 * @details	receive data of defined len through i2c from slave device which slave address is slv_addr.
 * @param[out]	data	pointer to data need to received by i2c
 * @param[in]	len	length of data to be received
 * @retval	>0	Byte count that was successfully received for poll method,
 * 			it might can't send that much due to @ref dev_i2c_info::err_state "different error state".
 * @retval	E_OBJ	Device object is not valid or not exists
 * @retval	E_CTX	Device is still in transfer state
 * @retval	E_PAR	Parameter is not valid
 * @retval	E_SYS	Can't receive data from hardware due to hardware issues, such as device is disabled
 */
/** @} */

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief	get an @ref dev_i2c "i2c device" by i2c device id.
 * 	For how to use i2c device hal refer to @ref DEVICE_HAL_I2C_DEVSTRUCT "Functions in i2c device structure"
 * @param[in]	i2c_id	id of i2c, defined by user
 * @retval	!NULL	pointer to an @ref dev_i2c "i2c device structure"
 * @retval	NULL	failed to find the i2c device by i2c_id
 * @note	need to implemented by user in user code
 */
extern DEV_I2C_PTR i2c_get_dev(int32_t i2c_id);

#ifdef __cplusplus
}
#endif

/** @} */
#endif /* __DEV_I2C_H__ */
